use sea_orm::{
    ActiveModelTrait, ColumnTrait, DatabaseConnection, DbErr, EntityTrait,
    IntoActiveModel, QueryFilter, QuerySelect, ActiveValue::Set
};
use crate::models::rbac::role::ActiveModel;
use chrono::Utc;
use uuid::Uuid;
use crate::models::rbac::role::{Model as Role, SafeRole, Entity, Column};

pub struct RoleService;

impl RoleService {
    pub async fn create(
        db: &DatabaseConnection,
        name: &str,
        description: Option<&str>,
        tenant_id: Option<i64>
    ) -> Result<Role, DbErr> {
        let now = Utc::now().naive_utc();
        let mut role = ActiveModel {
            id: Set(Uuid::new_v4().to_string()),
            name: Set(name.to_string()),
            description: Set(description.map(|s| s.to_string())),
            tenant_id: Set(tenant_id),
            create_time: Set(now),
            update_time: Set(now),
            ..Default::default()
        };

        role.insert(db).await
    }

    pub async fn update(
        db: &DatabaseConnection,
        id: &str,
        name: Option<&str>,
        description: Option<&str>,
        tenant_id: Option<i64>
    ) -> Result<Role, DbErr> {
        let mut role = Entity::find_by_id(id)
            .one(db)
            .await?
            .ok_or(DbErr::RecordNotFound("Role not found".to_string()))?
            .into_active_model();

        if let Some(name) = name {
            role.name = Set(name.to_string());
        }
        if let Some(desc) = description {
            role.description = Set(Some(desc.to_string()));
        }
        role.update_time = Set(Utc::now().naive_utc());

        role.update(db).await
    }

    pub async fn delete(
        db: &DatabaseConnection,
        id: &str,
        tenant_id: Option<i64>
    ) -> Result<u64, DbErr> {
        let res = Entity::delete_many()
            .filter(Column::Id.eq(id))
            .filter(Column::TenantId.eq(tenant_id))
            .exec(db)
            .await?;

        Ok(res.rows_affected)
    }

    pub async fn find_by_id(
        db: &DatabaseConnection,
        id: &str,
        tenant_id: Option<i64>
    ) -> Result<Option<Role>, DbErr> {
        Entity::find()
            .filter(Column::Id.eq(id))
            .filter(Column::TenantId.eq(tenant_id))
            .one(db)
            .await
    }

    pub async fn find_all(
        db: &DatabaseConnection,
        tenant_id: Option<i64>
    ) -> Result<Vec<SafeRole>, DbErr> {
        let roles = Entity::find()
            .filter(Column::TenantId.eq(tenant_id))
            .all(db)
            .await?;

        Ok(roles.into_iter().map(|r| SafeRole {
            id: r.id,
            name: r.name,
            description: r.description,
            tenant_id: r.tenant_id,
        }).collect())
    }
}
